﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Bluetooth_Fan.BluetoothFan.Classes;
using Bluetooth_Fan.Classes;
using System.IO.Ports;
using System.Threading;
using System.ComponentModel;
using System.Runtime.InteropServices;
using Bluetooth_Fan.HardwareInfo;
using System.Diagnostics;
using System.IO;




namespace Bluetooth_Fan.DeviceControl
{

    #region mStructures data
    public class DeRunTime
    {
        public UInt32 RunTime;
        public UInt32 EndTime;
    }
    public class DeviceStatus
    {
        /// <summary>
        /// 设备控制的数量
        /// </summary>
        public UInt16 DeviceNumber;
        /// <summary>
        /// 设备最大PWM值
        /// </summary>
        public static readonly UInt16 DevicePwmValMax = 1000;
        /// <summary>
        /// 设备PWM分为多少段
        /// </summary>
        public static readonly UInt16 DebicePwmSec = 10;

        /// <summary>
        /// 设备运行时间
        /// </summary>
        public UInt32 DeviceRuntime;
        /// <summary>
        /// 每个设备对应的PWM值
        /// </summary>
        public Int16[] mPwmVal;

        /// <summary>
        /// 设备运行时间
        /// </summary>
        public DeRunTime[] DeRunTim;
        public DeviceStatus()
        {
            mPwmVal = new Int16[2];
            DeRunTim = new DeRunTime[2];
            for (int i = 0; i < mPwmVal.Length; i++)
            {
                mPwmVal[i] = new Int16();
            }

            for (int i = 0; i < DeRunTim.Length; i++)
            {
                DeRunTim[i] = new DeRunTime();
            }
        }
    }
    #endregion

    class Bluetooth_FanControl
    {

        #region 驱动设备公有属性
        public void AddControlCmm(CDeviceControlCMM CMM)
        {
            lock (ControlCmmStack)
            {
                ControlCmmStack.Push(CMM);
            }
        }

        private CDeviceControlCMM GetControlCmm()
        {
            CDeviceControlCMM CMM = null;
            lock (ControlCmmStack)
            {
                CMM = ControlCmmStack.Pop();
            }
            return CMM;
        }

        /// <summary>
        /// 控制命令 列队中是否有需要发送的命令
        /// </summary>
        public bool IsControlCmmQueueAvailable { get { return ControlCmmStack.Count > 0; } }

        #endregion



        #region 内部属性及公有属性

        private SerialPort _SerialPort;
        private Thread SerialPortThread;

        private Timer _Timer;

        /// <summary>
        /// 控制命令的栈 采用LIFO  主要是方便实现突发控制产生的冲突
        /// </summary>
        private readonly Stack<CDeviceControlCMM> ControlCmmStack = new Stack<CDeviceControlCMM>();

        #region 驱动设备属性
        private DeviceStatus _DeStatus = new DeviceStatus();
        /// <summary>
        /// 设备的状态及参数
        /// </summary>
        public DeviceStatus DeStatus { get { return _DeStatus; } }

        /// <summary>
        /// 设备0是否正转 及控制
        /// </summary>
        public bool mDe0Prograde
        {
            get { return _DeStatus.mPwmVal[0] >= 0; }
            set
            {
                if (mDe0Prograde == value)
                {
                    return;
                }
                if (IsDebiceConnect == false)
                {
                    return;
                }
                if (mDe0PwmVal == 0)
                {
                    return;
                }
                byte[] Data = new byte[2] { 0X00, 0X00 };
                if (value == false)  //反转
                {
                    Data[1] = 0X01;
                }
                AddControlCmm(new CDeviceControlCMM(SYS_USER_COMM_Enum.SET_MOTO_Direction_COMM, Data));
            }
        }
        /// <summary>
        /// 设置设备0的PWM值
        /// </summary>
        public Int16 mDe0PwmVal
        {
            get { return _DeStatus.mPwmVal[0]; }
            set
            {
                if (mDe0PwmVal == value)
                {
                    return;
                }
                if (IsDebiceConnect == false)
                {
                    return;
                }
                if (value > DeviceStatus.DevicePwmValMax)
                {
                    OnEvenError("PWM最大值为" + DeviceStatus.DevicePwmValMax);
                    return;
                }
                byte[] Data = new byte[3] { 0X00, 0X00, 0X00 };
                Array.Copy(BitConverter.GetBytes(value), 0, Data, 1, 2);
                AddControlCmm(new CDeviceControlCMM(SYS_USER_COMM_Enum.SET_MOTO_PWM_COMM, Data));
            }
        }
        /// <summary>
        /// 设置电机分段转速
        /// </summary>
        public Int16 mDe0PwmValSec
        {
            get { return (Int16)(mDe0PwmVal * DeviceStatus.DebicePwmSec / DeviceStatus.DevicePwmValMax); }
            set
            {
                if (IsDebiceConnect == false)
                {
                    return;
                }
                if (Math.Abs(value) > DeviceStatus.DebicePwmSec)
                {
                    var Exception = new Exception("档速错误");
                    OnEvenError(Exception.Message);
                    return;
                }
                byte[] Data = new byte[3] { 0X00, 0X00, 0X00 };
                Data[1] = (byte)((value > 0) ? 0x00 : 0x01);
                Data[2] = (byte)Math.Abs(value);
                AddControlCmm(new CDeviceControlCMM(SYS_USER_COMM_Enum.SET_MOTO_PWM_Section_COMM, Data));
            }
        }
        /// <summary>
        /// 设置设备0 运行时间
        /// </summary>
        public UInt16 mDe0RunTime
        {
            set
            {
                if (IsDebiceConnect == false)
                {
                    return;
                }
                byte[] Data = new byte[3] { 0X00, 0X00, 0X00 };
                Array.Copy(BitConverter.GetBytes(value), 0, Data, 1, 2);
                AddControlCmm(new CDeviceControlCMM(SYS_USER_COMM_Enum.SET_MOTO_RUN_TIME_COMM, Data));
            }
        }
        //设备1属性控制----------------------------------
        /// <summary>
        /// 设备0是否正转 及控制
        /// </summary>
        public bool mDe1Prograde
        {
            get { return _DeStatus.mPwmVal[1] >= 0; }
            set
            {
                if (mDe1Prograde == value)
                {
                    return;
                }
                if (IsDebiceConnect == false)
                {
                    return;
                }
                if (mDe1PwmVal == 0)
                {
                    return;
                }
                byte[] Data = new byte[2] { 0X01, 0X00 };
                if (value == false)  //反转
                {
                    Data[1] = 0X01;
                }
                AddControlCmm(new CDeviceControlCMM(SYS_USER_COMM_Enum.SET_MOTO_Direction_COMM, Data));
            }
        }
        /// <summary>
        /// 设置设备0的PWM值
        /// </summary>
        public Int16 mDe1PwmVal
        {
            get { return _DeStatus.mPwmVal[1]; }
            set
            {
                if (mDe1PwmVal == value)
                {
                    return;
                }
                if (IsDebiceConnect == false)
                {
                    return;
                }
                if (value > DeviceStatus.DevicePwmValMax)
                {
                    OnEvenError("PWM最大值为" + DeviceStatus.DevicePwmValMax);
                    return;
                }
                byte[] Data = new byte[3] { 0X01, 0X00, 0X00 };
                Array.Copy(BitConverter.GetBytes(value), 0, Data, 1, 2);
                AddControlCmm(new CDeviceControlCMM(SYS_USER_COMM_Enum.SET_MOTO_PWM_COMM, Data));
            }
        }
        /// <summary>
        /// 设置电机分段转速
        /// </summary>
        public Int16 mDe1PwmValSec
        {
            get { return (Int16)(mDe1PwmVal * DeviceStatus.DebicePwmSec / DeviceStatus.DevicePwmValMax); }
            set
            {
                if (IsDebiceConnect == false)
                {
                    return;
                }
                if (Math.Abs(value) > DeviceStatus.DebicePwmSec)
                {
                    var Exception = new Exception("档速错误");
                    OnEvenError(Exception.Message);
                    return;
                }
                byte[] Data = new byte[3] { 0X01, 0X00, 0X00 };
                Data[1] = (byte)((value > 0) ? 0x00 : 0x01);
                Data[2] = (byte)Math.Abs(value);
                AddControlCmm(new CDeviceControlCMM(SYS_USER_COMM_Enum.SET_MOTO_PWM_Section_COMM, Data));
            }
        }
        public UInt16 mDe1RunTime
        {
            set
            {
                if (IsDebiceConnect == false)
                {
                    return;
                }
                byte[] Data = new byte[3] { 0X01, 0X00, 0X00 };
                Array.Copy(BitConverter.GetBytes(value), 0, Data, 1, 2);
                AddControlCmm(new CDeviceControlCMM(SYS_USER_COMM_Enum.SET_MOTO_RUN_TIME_COMM, Data));
            }
        }
        #endregion

        private bool _DebiceConnect = false; //连接标记

        /// <summary>
        /// 当前设备是否已连接
        /// </summary>
        public bool IsDebiceConnect
        {
            get { return _DebiceConnect; }
            set
            {
                if (_DebiceConnect == value)
                {
                    OnEvenDebug("连接状态不用处理");
                    return;
                }
                try
                {
                    if (value == true)  //打开
                    {

                        _SerialPort = new SerialPort(_SeriPortName, _SeriPortBaudRate);
                        _SerialPort.Open();
                        SerialPortThread = new Thread(SeriaportThreadTask);
                        SerialPortThread.IsBackground = true;
                        _Timer = new Timer(obj =>
                        {
                            AddControlCmm(new CDeviceControlCMM(SYS_USER_COMM_Enum.Rep_SYS_RUN_STA, null)); //在列队中加入控制命令
                            AddControlCmm(new CDeviceControlCMM(SYS_USER_COMM_Enum.Rep_SYS_State, null)); //在列队中加入控制命令
                        }, null, 300, 300);
                        _DebiceConnect = value;
                        SerialPortThread.Start();
                    }
                    else //断开
                    {
                        _DebiceConnect = value;  //先赋值 是为了方便在串口线程中检查是串口拔出产生的异常还是关闭串口引发的异常
                        if (_SerialPort.IsOpen)
                        {
                            _SerialPort.Close();
                        }
                        if (SerialPortThread.IsAlive)
                        {
                            SerialPortThread.Abort();
                        }
                    }
                    OnEvenDebug("连接状态为: " + _DebiceConnect);
                }
                catch (Exception er)
                {
                    OnEvenError(er.Message);
                    OnEvenDebug(er.Message);
                }
            }
        }

        private string _SeriPortName = null;
        /// <summary>
        /// 设置串口号
        /// </summary>
        public string SeriPortName
        {
            get { return _SeriPortName; }
            set
            {
                if (IsDebiceConnect)
                {
                    OnEvenError("请先关闭串口");
                    return;
                }
                _SeriPortName = value;
            }
        }

        private Int32 _SeriPortBaudRate = 0;
        public Int32 SeriPortBaudRate
        {
            get { return _SeriPortBaudRate; }
            set
            {
                if (IsDebiceConnect)
                {
                    OnEvenError("请先关闭串口");
                    return;
                }
                _SeriPortBaudRate = value;
            }
        }

        #endregion

        #region 事件及委托

        public event Action<string> EvenDebug;
        private void OnEvenDebug(string str)
        {
            Debug.WriteLine(str);
            if (EvenDebug!=null)
            {
                EvenDebug(str);
            }
        }

        /// <summary>
        /// 错误事件
        /// </summary>
        public event Action<object, string> EvenError;
        private void OnEvenError(string str)
        {
            if (EvenError != null)
            {
                EvenError(this, str);
            }
        }

        /// <summary>
        /// 设备ADC采集变更事件  1字节命令  1字节数据长度  + X字节数据
        /// </summary>
        public event Action<object, byte[]> EvenDeADCStats;
        private void OnEvenDeADCStats(byte[] Data)
        {
            if (EvenDeADCStats!=null)
            {
                EvenDeADCStats(this, Data);
            }
        }

        /// <summary>
        /// 设备状态变更事件
        /// </summary>
        public event Action<object, DeviceStatus> EvenDeChangeStatus;
        private void OnEvenDeChangeStatus(DeviceStatus desta)
        {
            if (EvenDeChangeStatus != null)
            {
                EvenDeChangeStatus(this, desta);
            }
        }

        /// <summary>
        /// 设备连接状态变更事件
        /// </summary>
        public event Action<object, bool> EvenChangeConnect;
        private void OnEvenChangeConnect(bool sta)
        {
            OnEvenDebug("连接变更事件：" + sta);
            if (EvenChangeConnect != null)
            {
                EvenChangeConnect(this, sta);
            }
        }
        #endregion



        #region 公用接口

        #endregion

        #region 内部私有函数
        /// <summary>
        /// 串口接收数据 及解析线程
        /// </summary>
        private void SeriaportThreadTask()
        {
            OnEvenDebug("开始运行串口线程 当前连接状态为 ：" +IsDebiceConnect);
            OnEvenChangeConnect(IsDebiceConnect);
            CDeviceControlCMM DeControlCMM = null;
            byte[] Data;
            try
            {
                while (true)
                {
                    if (IsControlCmmQueueAvailable)   //如果栈中有需要发送的命令
                    {
                        DeControlCMM = GetControlCmm();  //得到列队中的命令
                       lock (_SerialPort)
                        {
                            _SerialPort.Write(DeControlCMM.MessageData, 0, DeControlCMM.MessageData.Length);
                            OnEvenDebug("Write Data: " + CHardwareInfo.ToHexString(DeControlCMM.MessageData));
                            OnEvenDebug("Write Data length: " + DeControlCMM.MessageData.Length);
                            byte[] Buff = new byte[256];
                           
                            IAsyncResult IAsyncRe = _SerialPort.BaseStream.BeginRead(Buff, 0, 256, null, null); //接收1个字节
                            if (IAsyncRe.AsyncWaitHandle.WaitOne(100, false) == false)  //等待100MS  如果没有收到应答 则重新发送 如果收到信号 即使是一个字节则返回TRUTE
                            {
                                OnEvenDebug("0X" + ((byte)DeControlCMM.Command).ToString("X2") + "命令无应答");
                                continue;
                            }
                            int Count = _SerialPort.BaseStream.EndRead(IAsyncRe); //得到收到的数据长度  
                            Thread.Sleep(1);
                            int SerCount = _SerialPort.BytesToRead;   //得到缓存区数据长度
                            Data = new byte[Count + SerCount]; //真正接收到的数据大小为  前面接收到的长度加上缓冲器数据长度
                            Array.Copy(Buff, Data, Count); //拷贝之前异步读取的数据长度
                            _SerialPort.Read(Data, Count, SerCount);  //拷贝缓存区数据
                        }
                        OnEvenDebug("Read Data: " + CHardwareInfo.ToHexString(Data));
                        OnEvenDebug("Read Data length: " + Data.Length);
                        byte[] CommData = new byte[1]; //解析后的数据缓存   1字节命令 1字节数据长度  X字节数据
                        int Length = 0;
                        CmmErrCode ErrCode = CmmErrCode.ErrOk;
                        if ((ErrCode = CDeviceControlCMM.IsDeviceControlCMM(Data, ref CommData, ref Length)) != CmmErrCode.ErrOk)
                        {
                            OnEvenDebug("ErrCode :" + ErrCode);
                            OnEvenDebug(CHardwareInfo.ToHexString(Data));
                            OnEvenDebug("Lenth:" + Length);
                            Thread.Sleep(100);
                            continue;
                        }
                        //开始数据解析 -----------------------------------
                        OnEvenDebug("ACK DATA: " + CHardwareInfo.ToHexString(CommData));
                        OnEvenDebug("ACK DATA Length: " + Length);
                        if (CommData[0] != (byte)DeControlCMM.Command)
                        {
                            OnEvenDebug("0X" + ((byte)DeControlCMM.Command).ToString("X2") + "命令应答错误");
                            OnEvenDebug("返回应答命令为 0X" + CommData[0].ToString("X2"));
                        }
                        DeCmmAnalysis(CommData);  //数据解析
                    }
                    else
                    {
                        Thread.Sleep(100);
                    }       
                }
            }
            catch (Exception er)   //触发异常的可能是终止线程 也可能是 串口拔出 
            {
                if (IsDebiceConnect == true)  //如果当前状态为连接  但是产生了异常 则为串口拔出
                {
                    OnEvenError("串口被拔出");
                    OnEvenDebug("串口被拔出");
                    IsDebiceConnect = false; //标记串口已断开
                }
                if (_Timer!=null)
                {
                  _Timer.Dispose();//释放定时器资源
                }
                OnEvenDebug("串口线程关闭");
                OnEvenDebug(er.Message);
                ControlCmmStack.Clear();  //清楚所有对象
                OnEvenChangeConnect(IsDebiceConnect); //执行连接变更事件
            }
        }

        /// <summary>
        /// 解析下位机发过来的数据
        /// </summary>
        /// <param name="CmmData">命令1字节 + 数据长度1字节 +数据</param>
        private void DeCmmAnalysis(byte[] CmmData)
        {
            SYS_USER_COMM_Enum UserComm = (SYS_USER_COMM_Enum)CmmData[0];
            byte[] Userdata = new byte[CmmData.Length - 2];
            Array.Copy(CmmData, 2, Userdata, 0, Userdata.Length);   //拷贝数据段
            OnEvenDebug("DeCmmAnalysis userdata: " + CHardwareInfo.ToHexString(Userdata));
            switch (UserComm)
            {
                case SYS_USER_COMM_Enum.SET_Reserve:
                case SYS_USER_COMM_Enum.SET_MOTO_PWM_Section_COMM:
                case SYS_USER_COMM_Enum.SET_MOTO_PWM_COMM:
                case SYS_USER_COMM_Enum.SET_MOTO_RUN_TIME_COMM:
                case SYS_USER_COMM_Enum.SET_MOTO_Direction_COMM:
                    break;
                case SYS_USER_COMM_Enum.Rep_SYS_RUN_STA:
                    string Number = string.Empty;
                    for (int i = 3; i >= 0; i--)
                    {
                        Number += Userdata[i].ToString("X2");
                    }
                    _DeStatus.DeviceRuntime = Convert.ToUInt32(Number, 16) / 1000; //得到运行时间  单位：秒
                    _DeStatus.DeviceNumber = (UInt16)Userdata[4];  //电机数
                    for (int i = 0; i < _DeStatus.DeviceNumber; i++)
                    {
                        _DeStatus.mPwmVal[i] = BitConverter.ToInt16(Userdata, 6 * i + 5);
                        _DeStatus.DeRunTim[i].RunTime = BitConverter.ToUInt16(Userdata, 6 * i + 7);
                        _DeStatus.DeRunTim[i].EndTime = BitConverter.ToUInt16(Userdata, 6 * i + 9);
                    }
                    //触发设备状态变更事件
                    OnEvenDeChangeStatus(_DeStatus);
                    break;
                case SYS_USER_COMM_Enum.Rep_SYS_State:
                    OnEvenDeADCStats(CmmData);
                    break;
                case SYS_USER_COMM_Enum.Rep_SYS_VER:
                    string Ver = Encoding.ASCII.GetString(Userdata);
                    OnEvenError(Ver);
                    OnEvenDebug(Ver);
                    break;
                default:
                    break;
            }
        }
        #endregion
    }
}
